{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "# Building Synapse Models\n",
    "\n",
    "[![Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/brainpy/brainpy/blob/master/docs_version2/tutorial_building/build_synapse_models.ipynb)\n",
    "[![Open in Kaggle](https://kaggle.com/static/images/open-in-kaggle.svg)](https://kaggle.com/kernels/welcome?src=https://github.com/brainpy/brainpy/blob/master/docs_version2/tutorial_building/build_synapse_models.ipynb)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "@[Chaoming Wang](https://github.com/chaoming0625)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "In BrainPy, synapse models can be created by several ways. In this section, we will talk about a structural building process with ``brainpy.dyn.TwoEndConn``, which is used to create models with pre- and post-synaptic neuron groups.\n",
    "A synapse model is decomposed into several components in ``brainpy.dyn.TwoEndConn``. In such a way, building a synapse model can follow a modular and composable programming interface.\n",
    "Fore more details of defining a general synapse model, please refer to ``brainpy.dyn.SynConn`` in [Tutorial: Customizing Synapse Models](./customize_synapse_models.ipynb)."
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-10-06T03:46:31.329410Z",
     "start_time": "2025-10-06T03:46:27.254181Z"
    }
   },
   "source": [
    "import brainpy as bp\n",
    "\n",
    "bp.math.set_platform('cpu')\n",
    "\n",
    "bp.__version__"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'3.0.0'"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 1
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "## Synaptic models with ``brainpy.TwoEndConn``"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "In general, ``brainpy.TwoEndConn`` is used to model synaptic models with the following form:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "$$\n",
    "\\begin{aligned}\n",
    "\\frac{dg}{dt} = f_{\\mathrm{dyn}}(g, t)&  \\,\\,  \\to \\, &\\text{dyanmics of the synaptic conductance} \\\\\n",
    "g_{\\mathrm{max}} = f_{\\mathrm{LTP}}(g_{\\mathrm{max}}, t)  & \\,\\,  \\to \\, &\\text{long-term plasticity on synaptic weights }\\\\\n",
    "g = f_{\\mathrm{STP}}(g, t)  & \\,\\,  \\to \\, &\\text{short-term plasticity on synaptic conductance}\\\\\n",
    "I_{\\mathrm{post}} = f_{\\mathrm{out}}(g_{\\mathrm{max}} * g, t) &  \\,\\,  \\to \\, &\\text{synaptic output onto post-synpatic neurons}\\\\\n",
    "\\end{aligned}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "where each synapse model has its dynamical conductance $g$, synaptic weight $g_{\\mathrm{max}}$, and\n",
    "- $I_{\\mathrm{post}}$ is the synaptic current onto the post-synaptic neurons,\n",
    "- $f_{\\mathrm{dyn}}$ is the function to compute synaptic dynamics,\n",
    "- $f_{\\mathrm{LTP}}$ is the function for computing synaptic long-term plasticity,\n",
    "- $f_{\\mathrm{STP}}$ is the function for computing synaptic short-term plasticity,\n",
    "- $f_{\\mathrm{out}}$ is the way to output synaptic currents on post-synaptic neurons."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "## Example 1: Exponential synapse model"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "For a exponential synapse model,\n",
    "\n",
    "$$\n",
    "\\frac{d g}{d t} = -\\frac{g}{\\tau_{decay}}+\\sum_{k} \\delta(t-t_{j}^{k}), \\, (1) \\\\\n",
    "I_{\\mathrm{post}}(t) = g_{\\mathrm{max}} * g * (V_{\\mathrm{post}}(t)-E),\n",
    "$$\n",
    "\n",
    "where its $f_{\\mathrm{dyn}}$ is defined as equation (1), its $f_{\\mathrm{LTP}}$ and $f_{\\mathrm{STP}}$ is the identity function $x = f(x)$, $f_{\\mathrm{out}}$ is defined as a conductance-based form with $(V_{\\mathrm{post}}(t)-E)$.\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "Therefore, in BrainPy, we can define this model as the following form:"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-10-06T03:46:31.551113Z",
     "start_time": "2025-10-06T03:46:31.347146Z"
    }
   },
   "source": [
    "# a pre-synaptic neuron which generate spike at 1 ms, 11 ms, 21 ms.\n",
    "pre = bp.neurons.SpikeTimeGroup(1, [1., 11., 21.], [0, 0, 0])\n",
    "\n",
    "# a post-synaptic integrator which integrate synaptic inputs\n",
    "post = bp.neurons.LeakyIntegrator(1)\n",
    "\n",
    "# the synaptic model we want, whose output function is defined with `bp.synouts.COBA`\n",
    "bp.synapses.Exponential(pre, post, bp.conn.All2All(),\n",
    "                        output=bp.synouts.COBA(E=0.))"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Exponential(name=Exponential0, mode=NonBatchingMode, \n",
       "            pre=SpikeTimeGroup0(mode=NonBatchingMode, size=(1,)), \n",
       "            post=LeakyIntegrator0(mode=NonBatchingMode, size=(1,)))"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 2
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "Similarly, an Exponential synapse model with the current-based output can be defined as:"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-10-06T03:46:31.563496Z",
     "start_time": "2025-10-06T03:46:31.558053Z"
    }
   },
   "source": [
    "bp.synapses.Exponential(pre, post, bp.conn.All2All(),\n",
    "                        output=bp.synouts.CUBA())"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Exponential(name=Exponential1, mode=NonBatchingMode, \n",
       "            pre=SpikeTimeGroup0(mode=NonBatchingMode, size=(1,)), \n",
       "            post=LeakyIntegrator0(mode=NonBatchingMode, size=(1,)))"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 3
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "## Example 2: NMDA synapse model"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "NMDA synapse model is different from other models, since its currents onto post-synaptic groups are regulated by magnesium. Specifically, the net NMDA receptor-mediated synaptic current is given by\n",
    "\n",
    "$$\n",
    "I_{\\mathrm{post}} = g_{\\mathrm{max}} \\cdot g(t) \\cdot (V(t)-E) \\cdot g_{\\infty}\n",
    "$$\n",
    "\n",
    "where $g_{\\infty}$ represents the fraction of channels that are not blocked by magnesium.\n",
    "\n",
    "$$\n",
    "g_{\\infty} = (1+{e}^{-\\alpha V}\n",
    "\\frac{[{Mg}^{2+}]_{o}} {\\beta})^{-1}\n",
    "$$\n",
    "\n",
    "Here $[{Mg}^{2+}]_{o}$ is the extracellular magnesium concentration, usually 1 mM."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "In BrainPy, we provide this kind of magnesium-mediated synaptic output with `brainpy.synouts.MgBlock`. Therefore, a NMDA synapse can be defined with:"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-10-06T03:46:31.586695Z",
     "start_time": "2025-10-06T03:46:31.579968Z"
    }
   },
   "source": [
    "bp.synapses.NMDA(pre, post, bp.conn.All2All(),\n",
    "                 output=bp.synouts.MgBlock(E=0., cc_Mg=1.2))"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "NMDA(name=NMDA1, mode=NonBatchingMode, \n",
       "     pre=SpikeTimeGroup0(mode=NonBatchingMode, size=(1,)), \n",
       "     post=LeakyIntegrator0(mode=NonBatchingMode, size=(1,)))"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 4
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "## Example 3: Synapse models with short-term plasticity"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "Short-term synaptic plasticity is ambitious in synapse dynamics. BrainPy provides ``brainpy.synplast.STD`` for short-term depression and ``brainpy.synplast.STP`` for general  short-term plasticity. Short-term synaptic plasticity can be added onto most of synaptic models in BrainPy. For instance, here we define AMPA, GABA, and NMDA synapse models used in (Guoshi Li, et, al., 2017) [1].\n",
    "\n",
    "- [1] Li, Guoshi, Craig S. Henriquez, and Flavio Fröhlich. \"Unified thalamic model generates multiple distinct oscillations with state-dependent entrainment by stimulation.\" PLoS computational biology 13.10 (2017): e1005797."
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-10-06T03:46:32.167036Z",
     "start_time": "2025-10-06T03:46:31.599818Z"
    }
   },
   "source": [
    "# AMPA synapse model with STD\n",
    "\n",
    "bp.synapses.AMPA(pre, post, bp.conn.FixedProb(0.3),\n",
    "                 stp=bp.synplast.STD(tau=700, U=0.07),\n",
    "                 output=bp.synouts.COBA(E=0.),\n",
    "                 alpha=0.94, beta=0.18, g_max=6e-3)"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AMPA(name=AMPA1, mode=NonBatchingMode, \n",
       "     pre=SpikeTimeGroup0(mode=NonBatchingMode, size=(1,)), \n",
       "     post=LeakyIntegrator0(mode=NonBatchingMode, size=(1,)))"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 5
  },
  {
   "cell_type": "code",
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-10-06T03:46:32.444224Z",
     "start_time": "2025-10-06T03:46:32.416287Z"
    }
   },
   "source": [
    "# GABA synapse model with STD\n",
    "\n",
    "bp.synapses.GABAa(pre, post, bp.conn.FixedProb(0.3),\n",
    "                  stp=bp.synplast.STD(tau=700, U=0.07),\n",
    "                  output=bp.synouts.COBA(E=-80),\n",
    "                  alpha=10.5, beta=0.166, g_max=3e-3)"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "GABAa(name=GABAa0, mode=NonBatchingMode, \n",
       "      pre=SpikeTimeGroup0(mode=NonBatchingMode, size=(1,)), \n",
       "      post=LeakyIntegrator0(mode=NonBatchingMode, size=(1,)))"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 6
  },
  {
   "cell_type": "code",
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-10-06T03:46:32.508751Z",
     "start_time": "2025-10-06T03:46:32.481451Z"
    }
   },
   "source": [
    "# NMDA synapse model with STD\n",
    "\n",
    "bp.synapses.NMDA(pre, post, bp.conn.FixedProb(0.3),\n",
    "                 stp=bp.synplast.STD(tau=700, U=0.07),\n",
    "                 output=bp.synouts.MgBlock(E=0., cc_Mg=1.2))"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "NMDA(name=NMDA3, mode=NonBatchingMode, \n",
       "     pre=SpikeTimeGroup0(mode=NonBatchingMode, size=(1,)), \n",
       "     post=LeakyIntegrator0(mode=NonBatchingMode, size=(1,)))"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 7
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "## Example 4: synapse models with long-term plasticity"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "TODO."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
